package fun.ipconfig.utils;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;


/**
 * 表格工具类, 支撑插入多页数据，支撑链式编程
 * @author gtinlian
 */
public class ExcelWorkbookUtils {
    private Workbook workbook = null;
    private static Logger logger = LoggerFactory.getLogger(ExcelWorkbookUtils.class);

    /**
     * 私有构造
     * @param workbook
     */
    private ExcelWorkbookUtils(Workbook workbook) {
        this.workbook = workbook;
        
    }

    /**
     * 创建实例静态方法 实现 Excel 200 之后版本的格式表格创建
     * @author gtinlian
     */
    public static ExcelWorkbookUtils getInstanceXlsx() {
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        if (workbook == null) {
            logger.error("创建SXSSFWorkbook实例失败");
            return null;
        }
        workbook.setCompressTempFiles(true);
        return new ExcelWorkbookUtils(workbook);
    }

    /**
     * 创建实例静态方法 实现 Excel 2003 之前版本的格式表格创建
     * @return
     * @author gtinlian
     */
    public static ExcelWorkbookUtils getInstanceXls() {
        HSSFWorkbook workbook = new HSSFWorkbook();
        if (workbook == null) {
            logger.error("创建SXSSFWorkbook实例失败");
            return null;
        }
        return new ExcelWorkbookUtils(workbook);
    }

    /**
     * 获取数据接口
     * @author gtinlian
     * @param <T>
     *
     */
    public interface IGetObj<T> {
        Object[] invoke(T f);
    }

    /**
     * 表格央视设置
     */
    public interface ISetStyle {
        void setCellStyle(CellStyle style, Font font);
    }

    /**
     * 配置sheet
     */
    public interface ISheet {
        void setSheet(Sheet sheet);
    }
    
    /**
     * 创建按页
     *
     * @author gtinlian
     * @param name 页标签名称
     * @return
     *
     */
    public SheetOperation createSheet(String name) {
        Sheet sheet = workbook.createSheet(name);
        return new SheetOperation(sheet);
    }

    /**
     * 将表格写入到一个流
     *
     * @author gtinlian
     * @param out
     * @return
     */
    public ExcelWorkbookUtils writerTo(OutputStream out) {
        if (workbook != null) {
            try {
                workbook.write(out);
                return this;
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("写入表格时失败 ! ");
                return this;
            }
        }
        logger.error("表格已经被关闭 ！");
        return this;
    }
    
    /**
     * 关闭操作
     *
     * @author gtinlian
     */
    public void close() {
        if (workbook != null) {
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        workbook = null;
    }

    /**
     * 页处理
     *
     * @author gtinlian
     */
    public class SheetOperation {
        private Sheet sheet;
        private int rowNumber = 0;
        private Font font = workbook.createFont();
        private CellStyle cellStyle = workbook.createCellStyle();

        private SheetOperation(Sheet sheet) {
            reset();
            this.sheet = sheet;
        }

        /**
         * 配置表格样式
         * @author gtinlian
         * @param iSheet
         * @return
         */
        public SheetOperation setSheet(ISheet iSheet) {
            iSheet.setSheet(this.sheet);
            return this;
        }

        /**
         * 设置头部信息
         * @author gtinlian
         * @param header 头部，处理
         * @return
         * @styleImpl 配置样式   将style 返回 (style,font,sheet) -> style
         */
        public SheetOperation setHeader(String[] header) {
            return setHeader(header, null);
        }

        public SheetOperation setHeader(String[] header, ISetStyle styleImpl) {
            if(styleImpl != null) {
                styleImpl.setCellStyle(cellStyle, font); 
            }
            addData(header, styleImpl);
            // 配置玩头部样式重置下默认样式
            if(styleImpl != null)
                reset();
            return this;
        }
        
        /**
         * 添加数据
         * @param data
         * @param styleImpl
         * @return
         */
        private SheetOperation addData(Object[] data, ISetStyle styleImpl) {
            Row r = sheet.createRow(rowNumber);
            for (int i = 0; i < data.length; i++) {
                Cell cell = r.createCell(i);
                if(data[i] != null) 
                    cell.setCellValue(data[i].toString());
                if (styleImpl != null) 
                    cell.setCellStyle(cellStyle);
            }
            rowNumber++;
            return this;
        }

        /**
         * @author gtinlian
         * 加入数据
         * @param dataList    传入数据
         * @param iGetObjImpl 需要提供获取Object[]的实现，f为T泛型  (<T> f)->{  return (new object[]{}); }
         * @return
         * 
         */
        public <T> SheetOperation foreach(List<T> dataList, IGetObj<T> iGetObjImpl) {
            try {
                return foreach(dataList, iGetObjImpl, null);
            }catch (Exception e){
                e.printStackTrace();
            }
            return this;
        }

        public <T> SheetOperation foreach(List<T> dataList, IGetObj<T> iGetObjImpl, ISetStyle style) {
            if(style != null) {
                style.setCellStyle(cellStyle, font);
                cellStyle.setFont(font);
            }
            if(dataList != null && dataList.size() > 0) {
                logger.debug("{}开始导出{}",sheet.getSheetName(),dataList.size());
                for (T rowData : dataList) {
                    logger.debug("导出: =>{}", rowData != null ? rowData : null);
                    addData(iGetObjImpl.invoke(rowData), style);
                }
                logger.debug("{}结束导出",sheet.getSheetName());
            }
            if(style != null) {
                reset();
            }
            return this;
        }

        /**
         * 返回工作区操作
         * @return
         */
        public ExcelWorkbookUtils end() {
            return ExcelWorkbookUtils.this;
        }

        /**
         *  Description: 重置
         * @author: gtinlian
         * @date: 2023/12/18
         * @version: v2.0.1.62
         */
        void reset(){
            font = workbook.createFont();
            cellStyle = workbook.createCellStyle();
        }
    }
    
    /**
     * 对象回收时自动关闭
     * @throws Throwable
     */
    @Override
    protected void finalize() throws Throwable {
        close();
        super.finalize();
    }
}